#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time   : 2023-09-09 19:30
# @Author : hard work
# @File    : stc_based.py
# @Description : stc father class
"""
基于思博伦STC的自动化测试平台，已经实现的功能：
    EthernetII，VLAN，dstMac & srcMac auto, IPV4，TCP，UDP
继承关系：
    stc_based.py   ---> stc的父类，所有子类必须继承此类，必须提供STC的安装路径
        |____ l2_traffic_util.py   ---> 继承了stc_based.py 拓展了ethII的相关功能
          |____ l3_traffic_util.py ---> 继承了l2_traffic_util.py 拓展了IP相关功能
            |____ l4_traffic_util.py ---> 继承了l3_traffic_util.py 拓展了TCP/UDP相关功能
参数说明：
    见init()方法
函数说明：
    stc_init()
     此处要调用子类中的方法，                  如：l2_traffic_util.py中的函数
      set_apply()                          应用工程设置
        set_enable_capture()               开启抓包
         set_save_result_file()            保存STC配置
          start_flow()                     开始打流
           set_flow_stop()                 停止打流
            set_save_capture_result_file() 设置抓包保存路径
             set_stc_destroy()             销毁工程
调用方法：
    子类调用父类
"""
import os
import sys
from time import gmtime, strftime
from stc_utils.py_util.stc_cfgs import stc_cfg
from stc_utils.py_util.StcPython import StcPython
from tools_dev_and_sys.sys_secure.check_host_status import check_host_stat1


class Stc_global(object):

    def __init__(self, stcInstallDir, stc_Chassis_addr, slot, port_TX, port_RX, port_RX_OB,port_RX_20,port_RX_16):
        """stcInstallDir：检测stc安装路径，并加到环境变量"""
        # 全局参数

        self.hPortTx = ''  # 17 发包
        """发送端口"""
        self.hPortRx = ""  # 18 收包
        """接收端口"""
        self.hPortRx_OB = "" # 19 监控口
        """接收端口监控口"""
        self.hPortRx_20 = "" # 20 监控口
        """接收端口监控口"""
        self.hPortRx_16 = "" # 16 监控口
        """接收端口监控口"""
        self.hGenerator = ""
        """发送端口下创建流"""
        self.hAnalyzer = ""
        """接收端口下接收流"""
        self.hAnalyzer_OB = ""
        """观察端口接收流"""
        self.hProject = ""
        """创建流的工程"""
        self.hCapture = ""
        """接收端口抓包"""
        self.hCapture_OB = ''
        """观察端口抓包"""
        self.hCapture_20 = ''
        """观察端口抓包"""
        self.hCapture_16 = ''
        """观察端口抓包"""
        self.hAnaResults = ""
        """接收端口开始发送流"""
        # self.hAnaResults_OB = ""
        """接收端口开始发送流_观察"""
        self.hGenResults = ""
        """发送端口创建流"""

        try:
            if os.path.exists(stcInstallDir):
                stcPythonlibDir = stcInstallDir + '/API/Python'
                os.environ['STC_PRIVATE_INSTALL_DIR'] = stcInstallDir
                sys.path.append(stcPythonlibDir)
            else:
                raise "stc install file not found"
        except FileNotFoundError as e:
            print("stc install file not found")
        except OSError:
            print("OSError error")

        self.stc = StcPython()
        self.stc_Chassis_addr = stc_Chassis_addr
        # res = check_host_stat1(self.stc_Chassis_addr)
        # if res:
        #     pass
        # else:
        #     raise f"{self.stc_Chassis_addr} is not online"
        self.slot = slot
        self.port_TX = port_TX
        self.port_RX = port_RX
        self.port_RX_OB = port_RX_OB
        self.port_RX_20 = port_RX_20
        self.port_RX_16 = port_RX_16

    def stc_init(self, log_path=r'F:\Result\stc_log\sample.log', level='DEBUG'):
        """
        #             DEBUG - Display DEBUG, INFO, WARN, and ERROR messages
        #             INFO  - Display INFO, WARN, and ERROR messages
        #             WARN  - Display WARN and ERROR messages
        #             ERROR - Display only ERROR messages
        """
        self.stc.config('automationoptions', logTo=log_path, logLevel=level)
        self.stc.log("INFO", "Starting Test")

        # Retrieve and display the current API version.
        print("SpirentTestCenter system version:\t", self.stc.get("system1", "version"))
        try:
            # Physical topology
            txPortLoc = "//%s/%s/%s" % (self.stc_Chassis_addr, self.slot, self.port_TX)
            rxPortLoc = "//%s/%s/%s" % (self.stc_Chassis_addr, self.slot, self.port_RX)
            rxPortLoc_OB = "//%s/%s/%s" % (self.stc_Chassis_addr, self.slot, self.port_RX_OB)
            rxPortLoc_20 = "//%s/%s/%s" % (self.stc_Chassis_addr, self.slot, self.port_RX_20)
            rxPortLoc_16 = "//%s/%s/%s" % (self.stc_Chassis_addr, self.slot, self.port_RX_16)
            # Create the root project object
            print("Creating project ...")
            self.hProject = self.stc.create("project")

            # Create ports
            print("Creating ports ...")
            self.hPortTx = self.stc.create("port", under=self.hProject, location=txPortLoc, useDefaultHost=False)
            self.hPortRx = self.stc.create("port", under=self.hProject, location=rxPortLoc, useDefaultHost=False)
            self.hPortRx_OB = self.stc.create("port", under=self.hProject, location=rxPortLoc_OB, useDefaultHost=False)
            self.hPortRx_20 = self.stc.create("port", under=self.hProject, location=rxPortLoc_20, useDefaultHost=False)
            self.hPortRx_16 = self.stc.create("port", under=self.hProject, location=rxPortLoc_16, useDefaultHost=False)
            # Configure physical interface.
            hPortTxCopperInterface = self.stc.create("EthernetFiber", under=self.hPortTx, AutoNegotiation=False,
                                                     Duplex="FULL", LineSpeed="SPEED_1G")
            hPortRxCopperInterface = self.stc.create("EthernetCopper", under=self.hPortRx, AutoNegotiation="FALSE",
                                                     Duplex="FULL", LineSpeed="SPEED_1G")
            # hPortRxCopperInterface_ob = self.stc.create("EthernetCopper", under=self.hPortRx_OB, AutoNegotiation="FALSE",
            #                                          Duplex="FULL", LineSpeed="SPEED_1G")

            print("Attaching ports ", txPortLoc, rxPortLoc, rxPortLoc_OB,rxPortLoc_20,rxPortLoc_16)
        except Exception as e:
            print('error happen!!!', e)
            raise 'stc port error'
        # print("Attaching ports ", txPortLoc, rxPortLoc)
        self.stc.perform("AttachPorts")

        # Apply the configuration.
        print("Apply configuration")
        self.stc.apply()

        # Retrieve the generator and analyzer objects.
        self.hGenerator = self.stc.get(self.hPortTx, "children-Generator")
        self.hAnalyzer = self.stc.get(self.hPortRx, "children-Analyzer")
        # self.hAnalyzer_OB = self.stc.get(self.hPortRx_OB, "children-Analyzer")

    def set_apply(self):
        print("Apply configuration")
        self.stc.apply()

    def set_enable_capture(self, ENABLE_CAPTURE=True, ENABLE_OB=True):
        if ENABLE_CAPTURE:
            print("\nStarting Capture...")

            # Create a capture object. Automatically created.
            self.hCapture = self.stc.get(self.hPortRx, "children-capture")
            self.stc.config(self.hCapture, mode="REGULAR_MODE", srcMode="TX_RX_MODE")
            self.stc.perform("CaptureStart", captureProxyId=self.hCapture)
        if ENABLE_OB:
            print("\nStarting OB Capture...")
            self.hCapture_OB = self.stc.get(self.hPortRx_OB, "children-capture")
            self.stc.config(self.hCapture_OB, mode="REGULAR_MODE", srcMode="TX_RX_MODE")
            self.stc.perform("CaptureStart", captureProxyId=self.hCapture_OB)

            print("\nStarting 20 Capture...")
            self.hCapture_20 = self.stc.get(self.hPortRx_20, "children-capture")
            self.stc.config(self.hCapture_20, mode="REGULAR_MODE", srcMode="TX_RX_MODE")
            self.stc.perform("CaptureStart", captureProxyId=self.hCapture_20)

            print("\nStarting 16 Capture...")
            self.hCapture_16 = self.stc.get(self.hPortRx_16, "children-capture")
            self.stc.config(self.hCapture_16, mode="REGULAR_MODE", srcMode="TX_RX_MODE")
            self.stc.perform("CaptureStart", captureProxyId=self.hCapture_16)

    def set_save_result_file(self, model="tcc", path='F:\Result\stc\sample.xml', resultsfilename="F:\Result"):
        # Save the configuration as an XML file. Can be imported into the GUI.
        if model == "xml":
            print("\nSave configuration as an XML file.")
            self.stc.perform("SaveAsXml", FileName=path)
        elif model == "tcc":
            print("\nSave configuration as an tcc file.")
            self.stc.perform("SaveToTcc", filename=path)
        # resultsfilename = os.path.abspath(resultsfilename)
        # print("Saving results to " + resultsfilename)
        # self.stc.perform("SaveResult", CollectResult="TRUE",
        #                  SaveDetailedResults="TRUE",
        #                  DatabaseConnectionString=resultsfilename,
        #                  OverwriteIfExist="TRUE")

    def start_flow(self, timeout=100):
        if timeout > 0:
            # Start the analyzer and generator.
            print("Start Analyzer")
            self.stc.perform("AnalyzerStart", AnalyzerList=self.hAnalyzer)
            print("Current analyzer state ", self.stc.get(self.hAnalyzer, "state"))

            # self.stc.perform("AnalyzerStart", AnalyzerList=self.hAnalyzer_OB)
            # print("Current analyzer state ", self.stc.get(self.hAnalyzer_OB, "state"))

            print("Start Generator")
            self.stc.perform("GeneratorStart", GeneratorList=self.hGenerator)
            print("Current generator state", self.stc.get(self.hGenerator, "state"))

            print("Wait 2 seconds ...")
            self.stc.sleep(2)

            print("Wait until generator stops ...")
            self.stc.waitUntilComplete(timeout=timeout)

            print("Current analyzer state ", self.stc.get(self.hAnalyzer, "state"))
            # print("Current analyzer state ", self.stc.get(self.hAnalyzer_OB, "state"))
            print("Current generator state ", self.stc.get(self.hGenerator, "state"))
            print("Stop Analyzer")
        else:
            raise "time wait short"

    def set_flow_stop(self):

        # Stop the generator.
        self.stc.perform("GeneratorStop", GeneratorList=self.hGenerator)

        # Stop the analyzer.
        self.stc.perform("AnalyzerStop", AnalyzerList=self.hAnalyzer)

        # Stop the ob analyzer
        # self.stc.perform("AnalyzerStop", AnalyzerList=self.hAnalyzer_OB)

        # Display some statistics.

        # Example of Direct-Descendant Notation ( DDN ) syntax. ( DDN starts with an object reference )
        print("Frames Counts:")
        print("\tSignature frames: ", self.stc.get("%s.AnalyzerPortResults(1)" % self.hAnalyzer, "sigFrameCount"))
        print("\tTotal frames: ", self.stc.get("%s.AnalyzerPortResults(1)" % self.hAnalyzer, "totalFrameCount"))

        # print("\tSignature frames: ", self.stc.get("%s.AnalyzerPortResults" % self.hAnalyzer_OB, "sigFrameCount"))
        # print("\tTotal frames: ", self.stc.get("%s.AnalyzerPortResults" % self.hAnalyzer_OB, "totalFrameCount"))

        # Example of Descendant-Attribute Notation ( DAN ) syntax. ( using explicit indeces )
        # print("\tMinFrameLength: ", self.stc.get(self.hPortRx, "Analyzer(1).AnalyzerPortResults(1).minFrameLength"))
        # # Notice indexing is not necessary since there is only 1 child.
        # print("\tMaxFrameLength: ", self.stc.get(self.hPortRx, "Analyzer.AnalyzerPortResults.maxFrameLength"))

    def set_save_capture_result_file(self, path="F:\Result\cap\sample.pcap", path_ob='"F:\Result\cap\sample_ob.pcap"'):

        print(strftime("%Y-%m-%d %H:%M:%S", gmtime()), " Retrieving Captured frames...")

        self.stc.perform("CaptureStop", captureProxyId=self.hCapture)
        self.stc.perform("CaptureStop", captureProxyId=self.hCapture_OB)

        # Save captured frames to a file.
        self.stc.perform("CaptureDataSave", captureProxyId=self.hCapture, FileName=path,
                         FileNameFormat="PCAP", IsScap=False)
        self.stc.perform("CaptureDataSave", captureProxyId=self.hCapture_OB, FileName=path_ob,
                         FileNameFormat="PCAP", IsScap=False)

        print("Captured frames:\t", self.stc.get(self.hCapture, "PktCount"))
        print("Captured ob frames:\t", self.stc.get(self.hCapture_OB, "PktCount"))

    def set_save_capture_all(self,path_list):
        print(strftime("%Y-%m-%d %H:%M:%S", gmtime()), " Retrieving Captured frames...")

        self.stc.perform("CaptureStop", captureProxyId=self.hCapture)
        self.stc.perform("CaptureStop", captureProxyId=self.hCapture_OB)
        self.stc.perform("CaptureStop", captureProxyId=self.hCapture_20)
        self.stc.perform("CaptureStop", captureProxyId=self.hCapture_16)
        # Save captured frames to a file.
        self.stc.perform("CaptureDataSave", captureProxyId=self.hCapture, FileName=path_list[0],
                         FileNameFormat="PCAP", IsScap=False)
        self.stc.perform("CaptureDataSave", captureProxyId=self.hCapture_OB, FileName=path_list[1],
                         FileNameFormat="PCAP", IsScap=False)
        self.stc.perform("CaptureDataSave", captureProxyId=self.hCapture_20, FileName=path_list[2],
                         FileNameFormat="PCAP", IsScap=False)
        self.stc.perform("CaptureDataSave", captureProxyId=self.hCapture_16, FileName=path_list[3],
                         FileNameFormat="PCAP", IsScap=False)
        print("Captured 18 frames:\t", self.stc.get(self.hCapture, "PktCount"))
        print("Captured 19 frames:\t", self.stc.get(self.hCapture_OB, "PktCount"))
        print("Captured 20 frames:\t", self.stc.get(self.hCapture_20, "PktCount"))
        print("Captured 16 frames:\t", self.stc.get(self.hCapture_16, "PktCount"))

    def set_stc_destroy(self):

        # Unsubscribe from results
        print("Unsubscribe results ...")
        self.stc.unsubscribe(self.hAnaResults)
        self.stc.unsubscribe(self.hGenResults)

        # Disconnect from chassis, release ports, and reset configuration.
        print("Release ports and disconnect from chassis")
        self.stc.perform("ChassisDisconnectAll")
        self.stc.perform("ResetConfig")

        # Delete configuration
        print("Deleting project")
        self.stc.delete(self.hProject)

        self.stc.log("INFO", "Ending Test")

